from flask import request, jsonify, session, Response
from aps import app
from aps.models.item import *
from aps.models.itemversion import *
from aps.models.tipoitem import *
from aps.models.itematributovalor import *
from aps.models.proyectofase import *
from aps.models.atributo import *
from aps.models.relacion import *
from aps.models.solicituditem import *
from aps.models.solicitud import *
from aps.models.uploadedfile import *
from aps.models.usuario import *
from aps.views.historial import *
from aps.models.grafo import *



@app.route('/crear_item', methods=['GET', 'POST'])  
def crear_item():
    """
    Nos permite traer los parametros que fueron cargados por el usuario
    y guardarlos en la base de datos.
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    id_fase     = request.form['id_fase']
    id_tipoitem = request.form['id_tipoitem']
    # Tipo de item
    tipoitem   = bdsession.query(Tipoitem).filter_by(id=id_tipoitem).first()
    # Calculamos la numeracion dentro de la fase para el tipo de item
    maxnumfase = bdsession.query(func.max(Item.numfase)).filter_by(idtipoitem=id_tipoitem, idfase=id_fase).scalar()
    numfase    = ''
    if maxnumfase is None:
        numfase = tipoitem.prefijo + '-1'
    else:
        numfase = tipoitem.prefijo + '-' + str(int(str(maxnumfase[4:])) + 1)
    # Obtenemos los demas atributos base necesarios
    nombre       = request.form['1']
    descripcion  = request.form['2']
    prioridad    = request.form['3']
    complejidad  = request.form['4']
    version      = 1
    estado       = 'ACTIVO'
    id_lineabase = None
    # Creamos el nuevo item y guardamos en la BD
    model = Item(numfase, nombre, descripcion, version, prioridad, complejidad, estado, id_lineabase, id_tipoitem, id_fase)
    bdsession.add(model)
    bdsession.flush()

    # Recuperamos el item recien creado
    item    = bdsession.query(Item).filter_by(id=model.id).first()
    id_item = model.id
    print 'ID: ' + str(id_item)
 
    # Mantenemos solo los atributos del tipo item
    params = [it for it in request.form.keys() if it != u'id_tipoitem' and it != u'id_fase']
    
    # procesar las cosas que no son archivos
    for param in params:
        valor = bdsession.query(Atributo).filter_by(id=param).first().valordef if (request.form[param] == '' or request.form[param] == None) else request.form[param]
        # Creamos un objeto que contiene el valor del item
        item_valor = ItemAtributoValor(id_item, param, version, valor)
        item.valoratributo_x_version.append(item_valor)
    
    # procesar archivos, si hay
    
    for param in request.files.keys():
        valor = bdsession.query(Atributo).filter_by(id=param).first().valordef if (request.files[param] == '' or request.files[param] == None) else request.files[param]
        filename = ''
        if valor.__class__.__name__ == 'FileStorage':
            data     = valor.getvalue()
            model    = UploadedFile(id_item, param, valor.filename, data, len(data), 1)
            filename = valor.filename
        else:
            data     = 'default'
            model    = UploadedFile(id_item, param, 'default', data, len(data), 1)
            filename = 'default'
        # agregamos el modelo a la bd
        bdsession.add(model)
        # El valor del atributo es el nombre del archivo
        valor = filename
        # Creamos un objeto que contiene el valor del item
        item_valor = ItemAtributoValor(id_item, param, version, valor)
        item.valoratributo_x_version.append(item_valor)
    
    bdsession.merge(item)
   
    # Creamos una entrada en el historial
    log_it(id_item,session['usuario'],'item creado dentro del proyecto en su version 1, estado : ACTIVO')
    
    return Response('{success:true}')

@app.route('/modificar_item', methods=['GET', 'POST'])  
def modificar_item():
    """
    Nos permite traer los parametros que fueron modificados por el usuario
    y guardar los cambios en la base de datos.
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    id_item = request.form['id']
    
    # Obtenemos el item a modificar desde la BD
    item = bdsession.query(Item).filter_by(id=id_item).first()
    
    # Actualizacion de los atributos base del item
    numfase      = item.numfase
    nombre       = request.form['1']
    descripcion  = request.form['2']
    version      = item.version + 1
    prioridad    = request.form['3']
    complejidad  = request.form['4']
    
    estado       = item.estado
    id_lineabase = item.idlineabase
    id_tipoitem  = item.idtipoitem
    id_fase      = item.idfase
    
    # Actualizamos el item en la BD
    model = Item(numfase, nombre, descripcion, version, prioridad, complejidad, estado, id_lineabase, id_tipoitem, id_fase)
    model.id = id_item
    bdsession.merge(model)
    
    # Mantenemos solo los atributos del tipo item
    params = [it for it in request.form if it != u'id' and it != u'numfase']
    for param in params:
        # Definicion del atributo
        atributo = bdsession.query(Atributo).filter_by(id=int(param)).first()
        # Valor de este atributo en la version anterior del item
        prev_att = bdsession.query(ItemAtributoValor).filter_by(iditem=id_item,idatributo=atributo.id,version=version-1).first()
        # Controlamos la asignacion de los valores por defecto por si acaso
        valor = atributo.valordef if (request.form[param] == '' or request.form[param] == None) else request.form[param]
        
        # Si el atributo es ARCHIVO y tiene su valor por defecto, se mantiene el valor anterior
        # Esto significa que en el panel de modificar no se hizo absolutamente nada sobre el campo de tipo archivo
        if atributo.tipodato == u'ARCHIVO' and valor == atributo.valordef:
            att    = bdsession.query(UploadedFile).filter_by(iditem=id_item,idatributo=atributo.id,version=version-1).first()            
            if att != None:   
                model2 = UploadedFile(att.iditem,att.idatributo,att.filename,att.data,att.size,att.version+1)
                bdsession.add(model2)
                valor = att.filename
        # Si el atributo es ARCHIVO y tiene un nuevo valor
        # Esto significa que se realizo una accion sobre el campo de tipo archivo
        
        # Creamos el valor del atributo para el item en esta version
        item_valor = ItemAtributoValor(id_item, atributo.id, version, valor)
        item.valoratributo_x_version.append(item_valor)
    for param in request.files.keys():
        valor = bdsession.query(Atributo).filter_by(id=param).first().valordef if (request.files[param] == '' or request.files[param] == None) else request.files[param]
        print "adsafdshtfkujukiglgkydiyj"         
        filename = ''
        if valor.__class__.__name__ == 'FileStorage':
            data     = valor.getvalue()
            print data 
            model3    = UploadedFile(id_item, param, valor.filename, data, len(data),version)
            filename = valor.filename
            
            print "recibio un archivo"
        else:
            data     = 'default'
            model3    = UploadedFile(id_item, param, 'default', data, len(data), version)
            filename = 'default'
        bdsession.add(model3)
        # agregamos el modelo a la bd
        
        # El valor del atributo es el nombre del archivo
        valor = filename
        item_valor = ItemAtributoValor(id_item, param, version, valor)
        item.valoratributo_x_version.append(item_valor)
    
    # Obtenemos las relaciones del item y creamos un solo conjunto de relaciones
    relaciones   = []
    item.version = item.version - 1
    for x in item.get_antecesores('ALL')['validas']:
        relaciones.append(x)
    for x in item.get_sucesores('ALL')['validas']:
        relaciones.append(x)
    item.version = item.version + 1
    
    # Actualizamos las relaciones
    for r in relaciones:
        vorigen  = r.vorigen + 1 if int(r.idorigen) == int(item.id) else r.vorigen
        vdestino = r.vdestino + 1 if int(r.iddestino) == int(item.id) else r.vdestino
        model2   = Relacion(r.idorigen, r.iddestino, vorigen, vdestino, r.tipo, r.estado)
        bdsession.add(model2)
    
    # Cadena que indica que atributos han sido modificados
    attr = model.diff(model.version-1)
    asd = ''
    if len(attr) > 0:
        asd = 'item modificado dentro del proyecto, se han modificado los siguientes atributos: '
        for iav in attr:
            asd = asd + '<b>' + str(iav.atributo.nombre) + '</b>,'
        asd = asd[:-1] + '. La version actual es ' + str(model.version) + ', estado : ' + str(model.estado)
        # Creamos una entrada en el historial
        log_it(id_item,session['usuario'],asd)
    
    return Response('{success:true}')

@app.route('/consultar_item', methods=['GET', 'POST'])  
def consultar_item():
    """
    Nos permite traer los parametros de consulta(el filtro y el valor) y mostrar
    los itemes que cumplen con la condicion del filtro.
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """
    id_fase = request.args['idfase']
    # Obtenemos los items que pertenecen a la fase
    items = bdsession.query(Item).filter_by(idfase=id_fase).all()
    if items is None or len(items) == 0:
        return jsonify ({'success':True, 'data':[], 'total':0})
    # Descartamos los items eliminados
    items = [ it for it in items if it.estado != u'ELIMINADO' ]
    # Aplicamos un filtro si hubiere
    if request.args.has_key('filtro'):
        filtro    = request.args['filtro']
        valor     = request.args['valor']
        # Realizamos un filtro, si se necesita
        items  = [ it for it in items if str(it.__dict__[filtro]) == str(valor) ]
        print len(items)
        # verificamos si la consulta es de solicitud de cambio
        if request.args.has_key('solicitud'):
            #obtenes todos los id  de los items que ya estan en una solicitud
            solicituditem= None
            solicituditem= bdsession.query(SolicitudItem).all()
            for si in solicituditem:                
                print "hola hola"
                solicitud= bdsession.query(Solicitud).filter_by(id =si.idsolicitud).first()
                if solicitud.estado != u'APROBADO' and solicitud.estado != u'DESAPROBADO':
                    print "chau chau"
                    print solicitud.estado
                    iditem=si.iditem
                    items  = [ it for it in items if it.id != iditem]
    # Controlamos que los items tengan los hijos aprobados
    # Esto es utilizado solo en las lineas base
    if request.args.has_key('check'):
        items = [ it for it in items if it.hijos_aprobados() ]
    
    # Empaquetamos los datos para enviar
    data = []
    for item in items:
        element = {}
        element['id']          = item.id
        element['numfase']     = item.numfase
        element['fase']        = bdsession.query(ProyectoFase).filter_by(idfase=item.fase.id).first().orden
        element['nombre']      = item.nombre
        element['descripcion'] = item.descripcion
        element['version']     = item.version
        element['prioridad']   = item.prioridad
        element['complejidad'] = item.complejidad
        element['estado']      = item.estado
        data.append(element)
    return jsonify ({'success':True, 'data':data, 'total':len(data)})

@app.route('/eliminar_item', methods=['GET', 'POST'])  
def eliminar_item():
    """
    Nos permite traer el id del item a eliminar, eliminar las dependendcias
    del mismo con respecto a otras tablas y eliminar el registro de la base de datos.
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente y False en caso contrario
    """ 
    id   = request.form['id']
    item = bdsession.query(Item).filter_by(id=id).first()
    item.estado = 'ELIMINADO'
    bdsession.merge(item)
    
    # Eliminamos todas sus relaciones
    bdsession.query(Relacion).filter_by(idorigen=id).delete(synchronize_session=False)
    bdsession.query(Relacion).filter_by(iddestino=id).delete(synchronize_session=False)
    
    # Creamos una entrada en el historial
    log_it(id,session['usuario'],'item eliminado del proyecto, version al eliminarse ' + str(item.version) + ', estado : ELIMINADO')
    
    return jsonify ({'success' : True})

@app.route('/consultar_campos_crear_item', methods=['GET', 'POST'])  
def consultar_campos_crear_item():
    """
    Nos permite obtener los campos de un tipo item para generar un formulario de creacion
    para los items de una fase.
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente y False en caso contrario
    """
    id_tipoitem = request.form['id_tipoitem']
    tipoitem  = bdsession.query(Tipoitem).filter_by(id=id_tipoitem).first()
    data = []
    for atributo in tipoitem.atributos:
        item = {}
        item['name'] = atributo.atributo.id
        item['text'] = atributo.atributo.nombre
        item['type'] = atributo.atributo.tipodato
        item['defvalue'] = atributo.atributo.valordef
        item['nullable'] = atributo.atributo.id > 4 # true para los campos no base
        data.append(item)
    return jsonify ({'success':True, 'data':data, 'total':len(data)})
    
@app.route('/consultar_campos_modificar_item', methods=['GET', 'POST'])  
def consultar_campos_modificar_item():
    """
    Nos permite obtener los campos de un tipo item , y sus valores, para generar un formulario
    de modificacion para los items de una fase.
    @param request: objeto que encapsula la peticion del servidor
    @return: True si la accion se realizo correctamente y False en caso contrario
    """
    id_item = request.form['id_item']
    # Obtenemos el item a modificar desde la BD
    item    = bdsession.query(Item).filter_by(id=id_item).first()
    numfase = item.numfase
    version = item.version
    sentencia = 'SELECT * from ItemAtributoValor WHERE iditem=\'{0}\' and version=\'{1}\''.format(id_item, version)
    # Atributos de la ultima version
    atributos  = bdsession.query(ItemAtributoValor).from_statement(sentencia).all()
    data = []
    for atributo in atributos:
        item = {}
        item['name'] = atributo.atributo.id
        item['text'] = atributo.atributo.nombre
        item['type'] = atributo.atributo.tipodato
        item['value'] = atributo.valor
        item['nullable'] = atributo.atributo.id > 4 # true para los campos no base
        data.append(item)
    return jsonify ({'success':True, 'data':data, 'total':len(data), 'numfase':numfase})

@app.route('/consulta_item_x_fase', methods=['GET', 'POST'])  
def consulta_item_x_fase():
    """
    Nos permite obtener la lista detallada de item asignados a una fase
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    id_fase   = request.args['id_fase']
    sentencia = 'SELECT * from Item WHERE idfase={0}'.format(id_fase)
    items     = bdsession.query(Item).from_statement(sentencia).all()
    items = [ it for it in items if it.estado != u'ELIMINADO' ]
    data = []
    for item in items:
        element = {}
        element['id'] = item.id
        element['numfase'] = item.numfase
        element['fase'] = bdsession.query(ProyectoFase).filter_by(idfase=item.fase.id).first().orden
        element['nombre'] = item.nombre
        element['descripcion'] = item.descripcion
        element['version'] = item.version
        element['prioridad'] = item.prioridad
        element['complejidad'] = item.complejidad
        element['estado'] = item.estado
        data.append(element)
    return jsonify ({'success':True, 'data':data, 'total':len(data)})

@app.route('/consulta_item_x_lineabase', methods=['GET', 'POST'])  
def consulta_item_x_lineabase():
    """
    Nos permite obtener la lista detallada de item asignados a una lineabase
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    id_lineabase   = request.args['id_lineabase']
    sentencia = 'SELECT * from Item WHERE idlineabase={0}'.format(id_lineabase)
    items     = bdsession.query(Item).from_statement(sentencia).all()
    data = []
    for item in items:
        element = {}
        element['id'] = item.id
        element['numfase'] = item.numfase
        element['fase'] = bdsession.query(ProyectoFase).filter_by(idfase=item.fase.id).first().orden
        element['nombre'] = item.nombre
        element['descripcion'] = item.descripcion
        element['version'] = item.version
        element['prioridad'] = item.prioridad
        element['complejidad'] = item.complejidad
        element['estado'] = item.estado
        data.append(element)
    return jsonify ({'success':True, 'data':data, 'total':len(data)})

@app.route('/consultar_item_origen', methods=['GET', 'POST'])  
def consultar_item_origen():
    """
    Nos permite obtener los posibles items de destino para una relacion.
    @param request: objeto que encapsula la peticion del servidor
    @return: True si la accion se realizo correctamente y False en caso contrario
    """    
    if not request.args.has_key('proyecto') or not request.args.has_key('destino') or not request.args.has_key('tipo'):
        return jsonify ({'success':False, 'total':0, 'data':[]})
    
    # Parametros de entrada
    id_destino  = request.args['destino']
    tipo        = request.args['tipo']
    id_proyecto = request.args['proyecto']
    # Obtenemos el item de destino desde la BD
    item = bdsession.query(Item).filter_by(id=id_destino).first()
    # Seleccionamos los items segun el tipo de relacion
    origenes = None
    if tipo == 'PH':
        # Relacion padre-hijo
        origenes = bdsession.query(Item).filter_by(idfase=item.idfase).all()
    else:
        # Relacion antecesor-sucesor
        orden     = bdsession.query(ProyectoFase).filter_by(idproyecto=id_proyecto,idfase=item.idfase).first().orden
        pf        = bdsession.query(ProyectoFase).filter_by(idproyecto=id_proyecto,orden=(orden-1)).first()
        if pf is None:
            origenes = []
        else:
            fase_prev = pf.fase
            origenes = bdsession.query(Item).filter_by(idfase=fase_prev.id).all()
            origenes = [ x for x in origenes if x.estado == u'BLOQUEADO' ]
    # Descartamos los items en estado eliminado
    origenes = [x for x in origenes if x.estado != u'ELIMINADO' and x.id != int(id_destino)]
    # Empaquetamos los datos necesarios
    data = []
    for it in origenes:
        item = {}
        item['id'] = it.id
        item['nombre'] = it.nombre
        data.append(item)
    return jsonify ({'success':True, 'data':data, 'total':len(data)})
    
@app.route('/consultar_item_version', methods=['GET', 'POST'])  
def consultar_item_version():
    """
    Nos permite traer las distintas versiones del item seleccionado y mostrarlos en el grid
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """
    if not request.args.has_key('id_item'):
        return jsonify ({'success':False, 'total':0, 'data':[]})
    items = None
    id_item = request.args['id_item']
    item = bdsession.query(Item).filter_by(id=id_item).first()
    data = []
    for i in range(1, item.version):
        sentencia1 = 'SELECT * from Itematributovalor  WHERE iditem=\'{0}\' and idatributo= 1 and version=\'{1}\''.format(id_item, i)
        sentencia2 = 'SELECT * from Itematributovalor  WHERE iditem=\'{0}\' and idatributo= 2 and version=\'{1}\''.format(id_item, i)
        sentencia3 = 'SELECT * from Itematributovalor  WHERE iditem=\'{0}\' and idatributo= 3 and version=\'{1}\''.format(id_item, i)
        sentencia4 = 'SELECT * from Itematributovalor  WHERE iditem=\'{0}\' and idatributo= 4 and version=\'{1}\''.format(id_item, i)
        version = i
        iditem = item.id
        numfase= item.numfase
        estado = item.estado
        idfase = item.idfase
        idtipoitem = item.idtipoitem
        idlineabase = item.idlineabase
        nombre =  bdsession.query(ItemAtributoValor).from_statement(sentencia1).first().valor
        descripcion = bdsession.query(ItemAtributoValor).from_statement(sentencia2).first().valor
        prioridad = bdsession.query(ItemAtributoValor).from_statement(sentencia3).first().valor
        complejidad = bdsession.query(ItemAtributoValor).from_statement(sentencia4).first().valor
        model = ItemVersion(version, iditem, numfase, nombre, descripcion, prioridad, complejidad, estado, idlineabase, idtipoitem, idfase)
        bdsession.add(model)
        
        
    items = bdsession.query(ItemVersion).filter_by(iditem= id_item).all()
    data = []
    for item in items:
        element = {}
        element['version'] = item.version
        element['iditem'] = item.iditem
        element['numfase'] = item.numfase
        element['fase'] = bdsession.query(ProyectoFase).filter_by(idfase=item.idfase).first().orden
        element['nombre'] = item.nombre
        element['descripcion'] = item.descripcion
        element['version'] = item.version
        element['prioridad'] = item.prioridad
        element['complejidad'] = item.complejidad
        element['estado'] = item.estado
        data.append(element)
    for item in items:
        bdsession.delete(item)
        
    return jsonify ({'success':True, 'data':data, 'total':len(data)})

@app.route('/revertir_item', methods=['GET', 'POST'])  
def revertir_item():
    """
    Nos permite revertir los valores del atributo del item a una version anterior
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """
    id_item             = request.form['id_item'] 
    id_version          = request.form['version']    
    itematributovalores = None
    
    # Obtenemos el item a modificar desde la BD
    item = bdsession.query(Item).filter_by(id=id_item).first()
    sentencia1 = 'SELECT * from Itematributovalor  WHERE iditem=\'{0}\' and idatributo= 1 and version=\'{1}\''.format(id_item,id_version)
    sentencia2 = 'SELECT * from Itematributovalor  WHERE iditem=\'{0}\' and idatributo= 2 and version=\'{1}\''.format(id_item,id_version)
    sentencia3 = 'SELECT * from Itematributovalor  WHERE iditem=\'{0}\' and idatributo= 3 and version=\'{1}\''.format(id_item,id_version)
    sentencia4 = 'SELECT * from Itematributovalor  WHERE iditem=\'{0}\' and idatributo= 4 and version=\'{1}\''.format(id_item,id_version)
    
    # Actualizacion de los atributos base del item
    numfase      = item.numfase
    nombre       = bdsession.query(ItemAtributoValor).from_statement(sentencia1).first().valor
    descripcion  = bdsession.query(ItemAtributoValor).from_statement(sentencia2).first().valor
    prioridad    = bdsession.query(ItemAtributoValor).from_statement(sentencia3).first().valor
    complejidad  = bdsession.query(ItemAtributoValor).from_statement(sentencia4).first().valor
    version      = item.version + 1
    estado       = item.estado
    id_lineabase = item.idlineabase
    id_tipoitem  = item.idtipoitem
    id_fase      = item.idfase
    
    # Actualizamos el item en la BD
    model    = Item(numfase, nombre, descripcion, version, prioridad, complejidad, estado, id_lineabase, id_tipoitem, id_fase)
    model.id = id_item
    bdsession.merge(model)
    
    # Recuperamos el item modificado
    item = bdsession.query(Item).filter_by(idfase=id_fase,idtipoitem=id_tipoitem,numfase=numfase).first()
    
    # traemos los valores de los atributos segun la version seleccionada
    sentencia= 'SELECT * from Itematributovalor WHERE iditem=\'{0}\' and version=\'{1}\''.format(id_item,id_version) 
    itematributovalores = bdsession.query(ItemAtributoValor).from_statement(sentencia).all()
    # guardamos los valores de los atributos para esta version
    for i in itematributovalores:
        # definicion del atributo
        attr = bdsession.query(Atributo).filter_by(id=i.idatributo).first()
        if attr.tipodato == u'ARCHIVO' and i.valor!= bdsession.query(Atributo).filter_by(id=i.idatributo).first().valordef:
            # copiamos el atributo archivo
            uf    = bdsession.query(UploadedFile).filter_by(iditem=id_item,idatributo=i.idatributo,filename=i.valor,version=id_version).first()
            model = UploadedFile(uf.iditem,uf.idatributo,uf.filename,uf.data,uf.size,version)
            bdsession.add(model)
        item_valor = ItemAtributoValor(id_item, i.idatributo, version, i.valor)
        item.valoratributo_x_version.append(item_valor)
    bdsession.merge(item)
    
    # Creamos una entrada en el historial
    log_it(id_item,session['usuario'],'item revertido a la version ' + str(id_version) + ' desde la version ' + str(version-1) + ', version actual ' + str(version) +', estado : ' + str(estado))
    
    return jsonify ({'success':True})

@app.route('/consultar_item_revivir', methods=['GET', 'POST'])  
def consultar_item_revivir():
    """
    Nos permite traer los items de la fase que hayan sido eliminados para elegir el que desea revivir.
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """ 
    id_fase = request.args['idfase'] 
    usuarios = None
    items = bdsession.query(Item).filter(Item.idfase == id_fase,Item.estado == u'ELIMINADO').all()
    data = []
    for item in items:
        element = {}
        element['id'] = item.id
        element['numfase'] = item.numfase
        element['fase'] = bdsession.query(ProyectoFase).filter_by(idfase=item.fase.id).first().orden
        element['nombre'] = item.nombre
        element['descripcion'] = item.descripcion
        element['version'] = item.version
        element['prioridad'] = item.prioridad
        element['complejidad'] = item.complejidad
        element['estado'] = item.estado
        data.append(element)
    return jsonify ({'success':True, 'data':data, 'total':len(data)})

@app.route('/revivir_item', methods=['GET', 'POST'])  
def revivir_item():
    """
    Nos permite revivir un item que ya habia sido eliminado
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """
    id_item = request.form['id_item']
    
    # Obtenemos el item a modificar desde la BD
    item    = bdsession.query(Item).filter_by(id=id_item).first()
    
    # Actualizacion de los atributos base del item
    numfase      = item.numfase
    nombre       = item.nombre
    descripcion  = item.descripcion
    version      = item.version
    prioridad    = item.prioridad
    complejidad  = item.complejidad
    estado       = 'ACTIVO'
    id_lineabase = item.idlineabase
    id_tipoitem  = item.idtipoitem
    id_fase      = item.idfase
    
    # Actualizamos el item en la BD
    model = Item(numfase, nombre, descripcion, version, prioridad, complejidad, estado, id_lineabase, id_tipoitem, id_fase)
    model.id = id_item
    bdsession.merge(model)
    
    # Creamos una entrada en el historial
    log_it(id_item,session['usuario'],'item revivido dentro del proyecto, version actual ' + str(version) + ', estado : ACTIVO')
    
    return jsonify ({'success':True})    

@app.route('/terminar_item', methods=['GET', 'POST'])  
def terminar_item():
    """
    Nos permite modificar el estado de un item de ACTIVO a PENDIENTE de aprobacion.
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """
    id          = request.form['id']
    item        = bdsession.query(Item).filter_by(id=id).first()
    item.estado = 'PENDIENTE'
    bdsession.merge(item)
    
    
    # Creamos una entrada en el historial
    log_it(id,session['usuario'],'el item ha sido terminado, se espera la aprobacion del lider, estado : PENDIENTE')
    
    return jsonify ({'success' : True})
    
@app.route('/aprobar_item', methods=['GET', 'POST'])  
def aprobar_item():
    """
    Nos permite modificar el estado de un item de PENDIENTE a APROBADO.
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """
    ancentros  = None
    ancentros1 = None 
    id         = request.form['id']
    item       = bdsession.query(Item).filter_by(id=id).first()
    orden_fase = bdsession.query(ProyectoFase).filter_by(idfase=item.idfase).first().orden
    ancestros  = item.get_antecesores('AS')['validas']
    ancestros1 = item.get_antecesores('PH')['validas']
    
    if orden_fase == 1:
        if len(ancestros1) == 0 or item.padres_aprobados():
            item.estado = 'APROBADO'
            bdsession.merge(item)
            
        else: 
            return jsonify ({'success':False})
    else:
        if len(ancestros1) == 0 or item.padres_aprobados():
            if len(ancestros) == 0:
                return jsonify ({'success':False})
            item.estado = 'APROBADO'
            bdsession.merge(item)
            
        else:
            return jsonify ({'success':False})
            
    # Creamos una entrada en el historial
    log_it(id,session['usuario'],'el item ha sido aprobado por el lider del proyecto, estado : APROBADO')
    return jsonify ({'success' : True})

@app.route('/download_file')
def download_file():
    """
    Nos permite descargar un fichero adjunto a un item
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """
    
    filename   = str(request.args['f'])
    version    = str(request.args['v'])
    idatributo = str(request.args['a'])
    iditem     = str(request.args['i'])
    
    
    model = bdsession.query(UploadedFile).filter_by(iditem=iditem,idatributo=idatributo,filename=filename,version=version).first()   
    data  = model.data
    resp  = Response(content_type='*/*')
    resp.headers.add('Content-disposition', 'attachment; filename=' + filename)
    resp.headers.add('Content-Length', str(model.size))
    resp.data = data
    
    return resp

@app.route('/calcular_impacto_item', methods=['GET', 'POST'])  
def calcular_impacto_item():
    """
    Nos permite calcular el impacto tanto hacia atras, adelante o total de un item
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    id_item     = request.form['iditem']
    id_proyecto = request.form['idproyecto']
    
    item             = bdsession.query(Item).filter_by(id=id_item).first()
    grafo            = Grafo(int(id_proyecto))
    
    #complejidad del item
    impacto_adelante = grafo.impacto_hacia_adelante(int(id_item))
    impacto_atras    = grafo.impacto_hacia_atras(int(id_item))
    item_complejidad = item.complejidad
    impacto_total    = impacto_adelante + impacto_atras + item_complejidad
    
    #priodidad del item
    prioridad_adelante = grafo.prioridad_hacia_adelante(int(id_item))
    prioridad_atras    = grafo.prioridad_hacia_atras(int(id_item))
    item_prioridad = item.prioridad
    prioridad_total    = prioridad_adelante + prioridad_atras + item_prioridad
    
    
    
    url              = 'graficar_impacto_item?idproyecto={0}&iditem={1}'.format(id_proyecto,id_item)
    
    return jsonify ({'success':True, 'atras':impacto_atras, 'adelante':impacto_adelante, 'cmpl': item_complejidad, 'total':impacto_total, 'url':url,                     
                     'patras':prioridad_atras, 'padelante':prioridad_adelante, 'prio': item_prioridad, 'ptotal':prioridad_total})                     
                     
                     
                    


@app.route('/graficar_impacto_item', methods=['GET', 'POST'])  
def graficar_impacto_item():
    """
    Nos permite graficar el camino recorrido para calcular el impacto de un item
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    id_proyecto = request.args['idproyecto']
    id_item     = request.args['iditem']
    item        = bdsession.query(Item).filter_by(id=id_item).first()
    
    def to_dot_cluster(name,data):
        """
        Convierte una serie de datos relacionados con el calculo de impacto al formato DOT.
        @param name: Nombre para el elemento.
        @param data: Datos obtenidos del calculo de impacto.
        @return: String en formato DOT.
        """
        dot = 'subgraph cluster_' + str(name) + '{\n'
        dot += 'label="{0}";style = filled;\nfillcolor = skyblue4;\n'.format(data['fase'])
        dot += data['nodos']
        dot += data['cluster']
        dot += '}\n'
        dot += data['c2c']
        return dot
    
    count         = 0
    clusters_info = []
    g             = Grafo(int(id_proyecto))
    
    print g 
    # clusters hacia atras
    info  = g.cluster_atras_data(int(id_item))
    while info is not None:
        clusters_info.append(info)
        info = g.cluster_atras_data(None,info['items'])
    
    a     = clusters_info.pop(0)
    info  = g.cluster_adelante_data(int(id_item))
    info['nodos']   += a['nodos']
    info['nodos']   += '{0} [label="{1}({2})",color=white,style=filled,fillcolor=skyblue3,penwidth=2]\n'.format(item.id,item.nombre,item.complejidad)
    info['c2c']     += a['c2c']
    info['cluster'] += a['cluster']
    # clusters hacia adelante
    while info is not None:
        clusters_info.append(info)
        info = g.cluster_adelante_data(None,info['items'])
    
    # generamos el archivo DOT completo
    graph = 'graph project {\nbgcolor = slategray1; penwidth = 2; ranksep = 0.25; rankdir = LR;\n'
    count = 0
    for cluster in clusters_info:
        graph += to_dot_cluster(count,cluster)
        count = count + 1
    graph += '}'
    print "soy "
    print graph
    import os
    dotf = open('/tmp/graph.dot','wb')
    dotf.write(graph)
    dotf.close()
    pipe = os.popen('dot -Tpng /tmp/graph.dot -o /tmp/graph.png')
    pipe.close()
    
    pngf = open('/tmp/graph.png','rb')
    pngf.seek(0)
    data = ''
    while 1:
        tmp = pngf.read(1024)
        if not tmp:
            break
        data = data + tmp
    pngf.close()
    
    resp  = Response(content_type='image/png')
#     resp.header.add(('Content-Length',str(len(data))))
    
    resp.headers.add('Content-disposition', 'filename=' + 'grafico')
    resp.headers.add('Content-Length', str(len(data)))
    resp.data = data
    
    return resp

@app.route('/desaprobar_item', methods=['GET', 'POST'])  
def desaprobar_item():
    """
    Nos permite modificar el estado de un item de PENDIENTE a ACTIVO   de aprobacion.
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """
    id          = request.form['id']
    item        = bdsession.query(Item).filter_by(id=id).first()
    item.estado = 'ACTIVO'
    bdsession.merge(item)
    
    
    # Creamos una entrada en el historial
    log_it(id,session['usuario'],'El item fue desaprobado , estado : ACTIVO')
    
    return jsonify ({'success' : True})


@app.route('/consultar_modificar_solicitud', methods=['GET', 'POST'])  
def consultar_modificar_solicitud():
    """
    Nos permite traer los parametros de consulta(el filtro y el valor) y mostrar
    los itemes que cumplen con la condicion del filtro.
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """
    id_fase = request.args['idfase']
    idsolicitud = request.args['idsolicitud']
    # Obtenemos los items que pertenecen a la fase
    items = bdsession.query(Item).filter_by(idfase=id_fase).all()
    if items is None or len(items) == 0:
        return jsonify ({'success':True, 'data':[], 'total':0})
    # Descartamos los items eliminados
    items = [ it for it in items if it.estado != u'ELIMINADO' ]
    # Aplicamos un filtro si hubiere
    if request.args.has_key('filtro'):
        filtro    = request.args['filtro']
        valor     = request.args['valor']
        # Realizamos un filtro, si se necesita
        items  = [ it for it in items if str(it.__dict__[filtro]) == str(valor) ]
        # verificamos si la consulta es de solicitud de cambio
        if request.args.has_key('solicitud'):
            #obtenes todos los id  de los items que ya estan en una solicitud
            solicituditem= None
            solicituditem= bdsession.query(SolicitudItem).all()
            for si in solicituditem:                
                iditem=si.iditem
                items  = [ it for it in items if it.id != iditem]
    #obtenemos todos los items que ya estan en la solicitud a modificar
    sentencia='select * from Item where id  in (select iditem from SolicitudItem where idsolicitud=\'{0}\')'           
    items2 = bdsession.query(Item).from_statement(sentencia.format(idsolicitud)).all()

    # Controlamos que los items tengan los hijos aprobados
    # Esto es utilizado solo en las lineas base
    if request.args.has_key('check'):
        items = [ it for it in items if it.hijos_aprobados() ]
    
    # Empaquetamos los datos para enviar
    data = []
    #Empaquetamos los datos que ya pertenecen a la solicitud
    for item in items2:
        element = {}
        element['id']          = item.id
        element['numfase']     = item.numfase
        element['fase']        = bdsession.query(ProyectoFase).filter_by(idfase=item.fase.id).first().orden
        element['nombre']      = item.nombre
        element['descripcion'] = item.descripcion
        element['version']     = item.version
        element['prioridad']   = item.prioridad
        element['complejidad'] = item.complejidad
        element['estado']      = item.estado
        element['check']       = True 
        data.append(element)
    for item in items:
        element = {}
        element['id']          = item.id
        element['numfase']     = item.numfase
        element['fase']        = bdsession.query(ProyectoFase).filter_by(idfase=item.fase.id).first().orden
        element['nombre']      = item.nombre
        element['descripcion'] = item.descripcion
        element['version']     = item.version
        element['prioridad']   = item.prioridad
        element['complejidad'] = item.complejidad
        element['estado']      = item.estado
        element['check']       = False 
        data.append(element)
   
    return jsonify ({'success':True, 'data':data, 'total':len(data)})

@app.route('/consultar_cerrar_lb', methods=['GET', 'POST'])  
def consultar_cerrar_lb():
    """
    Nos permite traer los parametros de consulta(el filtro y el valor) y mostrar
    los itemes que cumplen con la condicion del filtro.
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """
    id_fase = request.args['idfase']
    id_lineabase = request.args['idlineabase']
    # Obtenemos los items que pertenecen a la fase
    items = bdsession.query(Item).filter_by(idfase=id_fase).all()
    if items is None or len(items) == 0:
        print "hola"
#         return jsonify ({'success':True, 'data':[], 'total':0})
    # Descartamos los items eliminados
    items = [ it for it in items if it.estado != u'ELIMINADO' ]
        
    # Aplicamos un filtro si hubiere
    if request.args.has_key('filtro'):
        filtro    = request.args['filtro']
        valor     = request.args['valor']
        # Realizamos un filtro, si se necesita
        items  = [ it for it in items if str(it.__dict__[filtro]) == str(valor) ]


    # Controlamos que los items tengan los hijos aprobados
    # Esto es utilizado solo en las lineas base
#     if request.args.has_key('check'):
#         items = [ it for it in items if it.hijos_aprobados() ]
    
    # Empaquetamos los datos para enviar
    sentencia = 'SELECT * from Item WHERE idlineabase={0}'.format(id_lineabase)
    itemslb     = bdsession.query(Item).from_statement(sentencia).all()
    data = []
    #Empaquetamos los datos que ya pertenecen a la linea base
    for item in itemslb:
        element = {}
        element['id'] = item.id
        element['numfase'] = item.numfase
        element['fase'] = bdsession.query(ProyectoFase).filter_by(idfase=item.fase.id).first().orden
        element['nombre'] = item.nombre
        element['descripcion'] = item.descripcion
        element['version'] = item.version
        element['prioridad'] = item.prioridad
        element['complejidad'] = item.complejidad
        element['estado'] = item.estado
        element['check']       = True
        data.append(element)


    for item in items:
        element = {}
        element['id']          = item.id
        element['numfase']     = item.numfase
        element['fase']        = bdsession.query(ProyectoFase).filter_by(idfase=item.fase.id).first().orden
        element['nombre']      = item.nombre
        element['descripcion'] = item.descripcion
        element['version']     = item.version
        element['prioridad']   = item.prioridad
        element['complejidad'] = item.complejidad
        element['estado']      = item.estado
        element['check']       = False 
        data.append(element)
   
    return jsonify ({'success':True, 'data':data, 'total':len(data)})

@app.route('/calcular_impacto_solicitud', methods=['GET', 'POST'])  
def calcular_impacto_solicitud():
    """
    Nos permite calcular el impacto tanto hacia atras, adelante o total de un item
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    
    idsolicitud     = request.form['idsolicitud']
    id_proyecto = request.form['idproyecto']
    #creamos el grafo del proyecto
    grafo    = Grafo(int(id_proyecto))
    #obtenemos todos los id de los items asociado a la solicitud
    itemsolicitud = bdsession.query(SolicitudItem).filter_by(idsolicitud=idsolicitud).all()
    impacto_total= 0
    for items in itemsolicitud:
  
        item             = bdsession.query(Item).filter_by(id=items.iditem).first()
        #complejidad
        impacto_adelante = grafo.impacto_hacia_adelante(item.id)
        impacto_atras    = grafo.impacto_hacia_atras(item.id)
        item_complejidad = item.complejidad
        impacto_total    = impacto_total + impacto_adelante + impacto_atras + item_complejidad
        
        #prioridad
        prioridad_adelante = grafo.prioridad_hacia_adelante(item.id)
        prioridad_atras    = grafo.prioridad_hacia_atras(item.id)
        item_prioridad = item.prioridad
        prioridad_total    = prioridad_adelante + prioridad_atras + item_prioridad
        
    return jsonify ({'success' : True,'total':impacto_total,'ptotal':prioridad_total})



@app.route('/puede_modificar_item', methods=['GET', 'POST'])  
def puede_modificar_item():
    """
    Nos permite saber si el item puede ser modificado por el usuario que solicita.
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """ 
    
    id_item = request.form['id_item']
    estado = request.form['estado'] 
    usuario_id = session['idusuario']
    itemsolicitud = None
    itemsolicitud = bdsession.query(SolicitudItem).order_by(SolicitudItem.iditem.desc()).first()
    print itemsolicitud
    print "oooo"
    if itemsolicitud is not None:
        if itemsolicitud.utilizado == 0:
            solicitud = None
            solicitud = bdsession.query(Solicitud).filter_by(id=itemsolicitud.idsolicitud).first()
            if solicitud.idusuario != usuario_id:
                return False
            else:
                itemsolicitud.utilizado = 1
                
            ##ver si el usuario realizo la solicitud
    
    return jsonify ({'success':True})
    

